In many domains, computer programs are being developed that need rendering of increasingly complex graphics scenes. These domains include games, genetic modeling, cinematic animation, simulations (e.g., flight simulators), and so on. Such complex graphics scenes are typically rendered using a graphics pipeline that generates a 2D image from 3D objects, shading equations, texture maps, tessellation techniques, camera angles, and so on. The computational resources needed to render a complex, pseudo-realistic 2D image in real time using such a pipeline typically exceeds the processing capabilities of the central processing unit (“CPU”) of many consumer computers such as desktops, laptops, tablets, smartphones, and so on. To provide the needed computational resources, many consumer computers include a graphics processing unit (“GPU”) that provides special-purpose hardware support for rendering images from graphics scenes.
To support the computational demands for rendering of the increasingly complex graphics scenes, GPU architectures are becoming increasingly complex. A typical GPU architecture includes various processing units for performing specific rendering tasks. These processing units may include a vertex shader, a hull shader, a geometry shader, a tessellation unit, a fragment shader, a clipping unit, a rasterizer, and so on. Early GPUs had fixed-function units for performing the various rendering tasks. GPUs now include programmable units for executing programs provided to the GPU as input. For example, a graphics device driver may compile a program written in a shading language to perform a specific type of shading function and provide the compiled program to the GPU by a processing unit. A GPU may also include memory for storing graphics primitives that define the 3D objects, texture maps, binning results, and so on.
GPU architectures are also increasingly complex and costly because they may have many programmable units (e.g., tens of shaders) and use sophisticated multithreading techniques to assign tasks to the programmable units. The hardware and software needed to manage such multithreading is very complex. In addition, the GPU architectures may use several special-purpose memory organizations, such as a binning memory and a hierarchical cache memory, to improve performance.
Because of the complexity of the GPU architectures, the GPUs are susceptible to various types of hardware errors that may prevent the successful rendering of an image. For example, these errors may be caused by a problem with the power supply, a hardware failure in a processing unit, a memory error (e.g., “bit rot”), and so on.
Some GPU architectures employ sophisticated techniques to minimize the effects of a hardware error. For example, a GPU architecture may track which processing units or memory locations have failed and automatically retry the rendering while avoiding the cause of the failure. Such sophisticated techniques further add to the complexity and consequently the cost of a GPU architecture. Because of the increased cost, these sophisticated techniques are only used on high-end GPUs and are not typically used on what are referred to as “commodity” GPUs. The high-end GPUs also have much more computational power than a commodity GPU. In general, a high-end GPU will typically support double precision arithmetic (e.g., 64 bits), whereas a commodity GPU will typically support only single precision arithmetic (e.g., 32 bits). As a result, high-end GPUs can cost orders of magnitude more than commodity GPUs.